package org.nvm.core;

import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import org.nvm.cfg.DefaultConfiguration;
import org.nvm.cfg.DictConfiguration;
import org.nvm.dic.Dictionary;

public class NVMSegmenter {

	private Reader input;
	
	private DictConfiguration cfg;
	
	private AnalyzeContext context;
	
	private List<ISegmenter> segmenters;
	
	private NVMArbitrator arbitrator;
	
	public NVMSegmenter(Reader input, boolean useSmart) {
		this.input = input;
		this.cfg = DefaultConfiguration.getInstance();
		this.cfg.setUseSmart(useSmart);
		init();
	}
	public NVMSegmenter(Reader input, DictConfiguration config) {
		this.input = input;
		this.cfg = config;
		init();
	}
	
	private void init() {
		Dictionary.initial(this.cfg);
		this.context = new AnalyzeContext(this.cfg);
		
		this.segmenters = load();
		
		this.arbitrator = new NVMArbitrator();
		
	}
	
	private List<ISegmenter> load() {
		List<ISegmenter> segs = new ArrayList<>();
		
		segs.add(new LetterSegmenter());
		segs.add(new CN_QuantifierSegmenter());
		segs.add(new CJKSegmenter());
		
		return segs;
	}
	
	public synchronized Lexeme next() throws IOException {
		Lexeme l = null;
		while((l = context.getNextLexeme()) == null) {
			int available = context.fillBuffer(input);
			if(available <= 0) {
				context.reset();
				return null;
			}
			
			context.initCursor();
			
			do {
				for(ISegmenter seg : segmenters) {
					seg.analyze(context);
				}

				if(context.neadReadBuffer()) {
					break;
				}

			} while(context.stepCursor());
			
			for(ISegmenter seg : segmenters) {
				seg.reset();
			}
			
			this.arbitrator.process(context, cfg.useSmart());
			
			context.processUnknowCJKChar();
			
			context.markBufferOffset();
		}
		
		return l;
	}
	
	public synchronized void reset(Reader input) {
		this.input = input;
		context.reset();
		for(ISegmenter segmenter : segmenters){
			segmenter.reset();
		}
	}
	
}
